﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace Pscx.Commands.TabExpansion.Handlers
{
    internal sealed class HistoryHandler : TabExpansionHandler
    {
        private const String GetHistoryById = "Get-History -Id $args[0] -ea SilentlyContinue";
        private const String GetHistoryByPattern = "Get-History -Count 32767 | Sort-Object -Descending Id";

        public HistoryHandler(GetTabExpansionCommand command) 
            : base(command)
        {
        }

        public override void TryExpand(String line, String word)
        {
            if ((word.Length > 1) && (word[0] == '#'))
            {
                var expansions = GetExpansions(word);

                if (expansions != null)
                {
                    foreach (var obj in expansions)
                    {
                        WriteExpansions(obj);
                    }
                }
            }
        }

        private IEnumerable<String> GetExpansions(String word)
        {
            var id = 0;
            var str = word.Substring(1);

            if (Int32.TryParse(str, NumberStyles.None, CultureInfo.InvariantCulture, out id))
            {
                if (id >= 1)
                {
                    return GetCommandLines(Invoke(GetHistoryById, id));
                }
            }

            return FilterCommandLines(GetCommandLines(Invoke(GetHistoryByPattern)), str);
        }

        private static IEnumerable<String> FilterCommandLines(IEnumerable<String> cmdlines, String pattern)
        {
            var pat = new WildcardPattern("*" + pattern + "*");

            foreach (var cmd in cmdlines)
            {
                if (pat.IsMatch(cmd))
                {
                    yield return cmd;
                }
            }
        }

        private static IEnumerable<String> GetCommandLines(IEnumerable<PSObject> objects)
        {
            if (objects != null)
            {
                foreach (var obj in objects)
                {
                    var prop = obj.Properties["CommandLine"];

                    if (prop != null)
                    {
                        var value = prop.Value;

                        if (value != null)
                        {
                            yield return value.ToString();
                        }
                    }
                }
            }
        }

        private IEnumerable<PSObject> Invoke(String script, params Object[] args)
        {
            return Command.InvokeCommand.InvokeScript(script, false, PipelineResultTypes.None, null, args);
        }
    }
}
